﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace CPPEI
{
    /// <summary>
    /// 错误编码管理
    /// 0xFFFF00-0xFFFFFF为系统使用
    /// </summary>
    public static class ErrorCodes
    {
        /// <summary>
        /// 没有错误
        /// </summary>
        public const int NoError = 0xFFFF00;

        private static List<ErrorCodeDictionary> s_dictionaries;
        private static List<ErrorCodeDictionary> s_sysDictionaries;

        private static object s_lockObj = new object();

        static ErrorCodes()
        {
            s_sysDictionaries = new List<ErrorCodeDictionary>();

            ErrorCodeDictionary dictionaryZHCN = new ErrorCodeDictionary("zh-cn");
            dictionaryZHCN.Add(NoError, "没有出现错误");
            s_sysDictionaries.Add(dictionaryZHCN);

            ErrorCodeDictionary dictionaryENUS = new ErrorCodeDictionary("en-us");
            dictionaryENUS.Add(NoError, "no error");
            s_sysDictionaries.Add(dictionaryENUS);
        }

        public static string GetSysMessage(int code, string language)
        {
            for (int index = 0; index < s_sysDictionaries.Count; index++)
            {
                if (string.Equals(s_sysDictionaries[index].Language, language, StringComparison.CurrentCultureIgnoreCase))
                {
                    object message = s_sysDictionaries[index].GetMessage(code);
                    if (message != null)
                    {
                        return (string)message;
                    }
                    break;
                }
            }
            return string.Format("Unknown error:0x{0:X6}", code);
        }

        public static string GetMessage(int code)
        {
            string language = System.Threading.Thread.CurrentThread.CurrentCulture.Name;
            if (code >= 0xffff00)
            {
                return GetSysMessage(code, language);
            }
            else
            {
                bool hasDictionary = false;
                if(s_dictionaries!=null)
                {
                    for (int index = 0; index < s_dictionaries.Count; index++)
                    {
                        if (string.Equals(s_dictionaries[index].Language, language, StringComparison.CurrentCultureIgnoreCase))
                        {
                            hasDictionary = true;
                            object message = s_dictionaries[index].GetMessage(code);
                            if (message != null)
                            {
                                return (string)message;
                            }
                            break;
                        }
                    }
                }

                if(!hasDictionary)
                {
                    lock (s_lockObj)
                    {
                        LoadErrorCodesFile(language);
                    }

                    for (int index = 0; index < s_dictionaries.Count; index++)
                    {
                        if (string.Equals(s_dictionaries[index].Language, language, StringComparison.CurrentCultureIgnoreCase))
                        {
                            hasDictionary = true;
                            object message = s_dictionaries[index].GetMessage(code);
                            if (message != null)
                            {
                                return (string)message;
                            }
                            break;
                        }
                    }
                }
            }
            return string.Format("Unknown error:0x{0:X6}", code);
        }

        private static void LoadErrorCodesFile(string language)
        {
            if(s_dictionaries == null)
            {
                s_dictionaries = new List<ErrorCodeDictionary>();
            }
            ErrorCodeDictionary dictionary = new ErrorCodeDictionary(language);

            string localsDirectory = string.Format("{0}\\bin\\locals\\", AppDomain.CurrentDomain.BaseDirectory);
            if(!Directory.Exists(localsDirectory))
            {
                return;
            }
            string endTag = string.Format(".error.{0}.xml", language);

            string[] files = Directory.GetFiles(localsDirectory);
            for (int index = 0; index < files.Length; index++)
            {
                string filePath = files[index];
                if (filePath.EndsWith(endTag, StringComparison.CurrentCultureIgnoreCase))
                {
                    try
                    {
                        // 读取文件
                        XmlDocument xmlDoc = new XmlDocument();
                        xmlDoc.Load(filePath);
                        XmlNodeList xErrorList = xmlDoc.SelectNodes("./errors/error");
                        for (int xErrorIndex = 0; xErrorIndex < xErrorList.Count; xErrorIndex++)
                        {
                            XmlNode xError = xErrorList[xErrorIndex];
                            int code = 0;
                            string message = null;
                            for (int subIndex = 0; subIndex < xError.ChildNodes.Count; subIndex++)
                            {
                                if (string.Equals(xError.ChildNodes[subIndex].Name, "code"))
                                {
                                    string errorCode = xError.ChildNodes[subIndex].InnerText;

                                    if (errorCode.StartsWith("0x"))
                                    {
                                        // hex
                                        errorCode = errorCode.Replace("0x", string.Empty);
                                        if (!int.TryParse(errorCode, System.Globalization.NumberStyles.AllowHexSpecifier, null, out code))
                                        {
                                            break; ;
                                        }
                                    }
                                    else
                                    {
                                        if (!int.TryParse(errorCode, out code))
                                        {
                                            break; ;
                                        }
                                    }
                                }
                                else if (string.Equals(xError.ChildNodes[subIndex].Name, "message"))
                                {
                                    message = xError.ChildNodes[subIndex].InnerText;
                                    if (string.IsNullOrEmpty(message))
                                    {
                                        break;
                                    }
                                }
                            }
                            if (code != 0 && !string.IsNullOrEmpty(message))
                            {
                                dictionary.Add(code, message);
                            }
                        }
                    }
                    catch (Exception ex)
                    {

                    }
                }
            }
            s_dictionaries.Add(dictionary);
        }
    }
}
